#
# Copyright (c) 2023 supercell
#
# SPDX-License-Identifier: BSD-3-Clause
#

# This is an example HTTP server which
# accepts a Markdown request and returns
# the parsed HTML.
require "ecr"
require "http"
require "log"

require "./default_markdown"

require "../src/luce.cr"

PORT = ENV.fetch("LUCE_PORT", "8080").to_i32

def serve_index(response : HTTP::Server::Response, params : URI::Params) : Nil
  response.status_code = 200
  response.content_type = "text/html"

  markdown = params.fetch("markdown", DEFAULT_MARKDOWN)
  extension_set = params.fetch("extension", "CommonMark")
  es = case extension_set
       when "CommonMark"
         Luce::ExtensionSet::COMMON_MARK
       when "GitHub"
         Luce::ExtensionSet::GITHUB_WEB
       else
         Luce::ExtensionSet::NONE
       end

  # `ren_markdown` is used in "index.ecr"
  # ameba:disable Lint/UselessAssign
  ren_markdown = Luce.to_html(markdown, extension_set: es)
  renderer = ECR.render "index.ecr"
  bytes = renderer.unsafe_byte_slice(0)
  response.content_length = bytes.size
  response.write(bytes)
end

def method_not_allowed(response : HTTP::Server::Response) : Nil
  response.headers["Allow"] = "GET"
  response.respond_with_status(405)
end

DEFAULT_PARAMS = URI::Params.new({"markdown" => [DEFAULT_MARKDOWN], "extension" => ["CommonMark"]})

def process_request(request : HTTP::Request) : URI::Params
  return DEFAULT_PARAMS if request.body.nil?
  body = request.body.not_nil!
  form = body.gets_to_end
  URI::Params.parse(form)
end

def plain(response : HTTP::Server::Response, resource : String) : Nil
  css = File.read(".#{resource}")
  response.status_code = 200
  css_bytes = css.unsafe_byte_slice(0)
  response.content_length = css_bytes.size
  response.write(css_bytes)
end

server = HTTP::Server.new do |context|
  # Probably not the best way to do this.
  case context.request.resource
  when "/preview"
    if context.request.method == "POST"
      params = process_request(context.request)
      serve_index(context.response, params)
    else
      method_not_allowed(context.response)
    end
  when "/", "/index.html"
    serve_index(context.response, DEFAULT_PARAMS)
  when /.*\.css/, /.*\.js/
    plain(context.response, context.request.resource)
  when /favicon/
    # There are probably other requests that should
    # just be ignored, but this is just an example.
    context.response.respond_with_status(404)
  else
    context.response.status_code = 301
    context.response.headers["Location"] = "/index.html"
  end

  # makes this example look official ;p
  Log.info { "#{context.request.method}: #{context.response.status_code} #{context.request.resource}" }
end

address = server.bind_tcp(PORT)

puts "Running Crystal #{Crystal::VERSION}"
puts "Listening on http://#{address}"
server.listen
